﻿using System.Collections.Generic;
using Alone.EnemyStates;
using Alone.GameObjects;
using Alone.GameObjects.Enemy;
using AloneLibrary.Services.Sound;
using Microsoft.Xna.Framework;

namespace Alone.Handlers
{

    /// <summary>
    /// Class EnemyStateManager keep track on all enemies' current states. 
    /// Inherits IEnemyStateManager
    /// </summary>
    public class EnemyStateManager : IEnemyStateManager
    {
        enum stateRank
        {
            kill,
            attack,
            flee,
            stray
        };

        private List<EnemyState> states = new List<EnemyState>();
        private List<EnemyState> selectedStates = new List<EnemyState>();
        private StrayState stray;
        private AttackingState attack;
        private KillingState kill;
        private FleeingState flee;
        private Game game;
        private ISoundManager soundHandler;

        /// <summary>
        /// Initializes a new instance of the <see cref="EnemyStateManager"/> class.
        /// </summary>
        /// <param name="game">The game.</param>
        public EnemyStateManager(Game game)
        {
            //game.Services.AddService(typeof(IEnemyStateManager), this);
            stray = new StrayState();
            attack = new AttackingState();
            kill = new KillingState();
            flee = new FleeingState();
            states.Add(stray);
            states.Add(kill);
            states.Add(flee);
            states.Add(attack);
            this.game = game;
            soundHandler = (ISoundManager)game.Services.GetService(typeof(ISoundManager));
        }

        /// <summary>
        /// Iterattes through all enemies and players and evaluates 
        /// all enemiestates and sets the most suited state for each enemy
        /// </summary>
        /// <param name="enemies">The enemies.</param>
        /// <param name="players">The players.</param>
        public void checkStatesAndUpdateEnemies(List<Enemy> enemies, List<BasePlayer> players)
        {
            float fuzzy = 0;
            float maxFuzzy;
            EnemyState tempState = new StrayState();
            foreach (Enemy enemy in enemies)
            {
                foreach (BasePlayer player in players)
                {
                    maxFuzzy = -10;
                    foreach (EnemyState state in states)
                    {
                        fuzzy = state.evaluate(enemy, enemies, player); // Returns a fuzzy value 0..1
                        if (fuzzy > maxFuzzy)
                        {
                            maxFuzzy = fuzzy;
                            tempState = state;
                        }
                    }
                    selectedStates.Add(tempState);
                }
                setState(enemy);
                selectedStates.Clear();
                enemy.CurrentState.doAI(enemy, enemies, players);
            }
        }

        /// <summary>
        /// Sets the current state of the enemy according to state priority.
        /// </summary>
        /// <param name="enemy">The enemy.</param>
        private void setState(Enemy enemy)
        {
            stateRank rank = stateRank.stray;
            int id = 0;
            foreach (EnemyState state in selectedStates)
            {
                if (state is KillingState)
                {
                    enemy.CurrentState = state; 
                    if (!soundHandler.IsPlaying("bite"))
                        soundHandler.Play("bite");
                    return;
                }

                else if (state is AttackingState)
                {
                    rank = stateRank.attack;
                    id = selectedStates.IndexOf(state);
                }
                else if (state is FleeingState && rank < stateRank.flee)
                {
                    rank = stateRank.flee;
                    id = selectedStates.IndexOf(state);
                }
                else if (state is StrayState && rank < stateRank.stray)
                {
                    rank = stateRank.flee;
                    id = selectedStates.IndexOf(state);
                }
            }
            enemy.CurrentState = selectedStates[id];
        }
    }
}

